import { Injectable } from '@nestjs/common';
import { createPublicKey, createVerify } from 'crypto';
import { Request, Response } from 'express'
import { OrderService } from 'src/order/order.service';
import { UtilsService } from 'src/utils/utils.service';
import { AliConfig } from 'src/pay/ali.config'

interface AliReturnUrlQuery {
    charset: string,
    out_trade_no: string,
    method: string,
    total_amount: string,
    sign: string,
    trade_no: string,
    auth_app_id: string,
    version: string,
    app_id: string,
    sign_type: string,
    seller_id: string,
    timestamp: string
}


@Injectable()
export class PayNoticeService {

    constructor(
        private readonly utilService: UtilsService,
        private readonly oderService: OrderService
    ) { }

    //处理小程序支付通知
    // async applets(body: any, request: Request, response: Response) {
    //     console.log('=================处理小程序支付通知===================');
    //     console.log(body);
    //     console.log('====================================');
    // }

    //处理微信支付通知
    async handlingNotifications(body: any, request: Request, response: Response) {
        const key = 'GIc55X7OmWp6IS470c10m25gkadZUvCd';//APIv3密钥
        const { data } = await this.utilService.getWechatSign('GET', '/v3/certificates');//获取平台证书需解密
        const serial_no = data[0].serial_no//商户当前所持有的 微信支付平台证书序列号
        const wechatpay_serial = request.headers['wechatpay-serial'] //微信支付平台证书序列号；验证签名前检查序列号是否跟商户当前所持有的 微信支付平台证书序列号一致。
        if (serial_no === wechatpay_serial) {//先对比证书序列号一致则解密证书
            const { nonce, associated_data, ciphertext } = data[0].encrypt_certificate;//解构证书信息
            const decrypt_certificate = this.utilService.getDecrypt(ciphertext, key, nonce, associated_data);//解密后证书
            const certificate_public_key = createPublicKey(decrypt_certificate).export({ type: 'pkcs1', format: 'pem' });//从解密证书中获取证书公钥
            let wechatPaySignature = request.headers['wechatpay-signature'] as string;//微信支付应答签名 需要验签 不需要base64解码
            //构造验签名串
            const wechatPayTimestamp = request.headers['wechatpay-timestamp'];//应答时间戳
            const wechatPayNonce = request.headers['wechatpay-nonce'];//应答随机串
            const pending_verification_str = `${wechatPayTimestamp}\n${wechatPayNonce}\n${JSON.stringify(body)}\n`;//待验证串
            //验签
            const verify = createVerify('RSA-SHA256');
            verify.update(pending_verification_str);
            verify.end();
            const result = verify.verify(certificate_public_key, wechatPaySignature, 'base64');//得到验签结果
            if (result) {
                const { algorithm, nonce, associated_data, ciphertext } = body.resource;//微信支付结果 通知的数据包括了加密的支付结果详情
                const decrypt_noticeParam = JSON.parse(this.utilService.getDecrypt(ciphertext, key, nonce, associated_data));//解密后的微信支付通知参数
                console.log(decrypt_noticeParam.out_trade_no);
                const order = await this.oderService.getOrderByNumber(decrypt_noticeParam.out_trade_no);// 获取订单
                console.log(order.id);

                if (order) {
                    if (order.pay_state === 'NOTPAY') {
                        if (decrypt_noticeParam.trade_state === 'SUCCESS') {
                            order.pay_state = decrypt_noticeParam.trade_state;
                            order.pay_state_desc = decrypt_noticeParam.trade_state_desc;
                            order.pay_method = 'wechat';
                            order.pay_success_time = decrypt_noticeParam.success_time;
                            order.receipt_price = parseFloat(decrypt_noticeParam.amount.payer_total) / 100;
                            const orderId = order.id;
                            delete order.id;
                            await this.oderService.update(orderId, order)
                        }
                    }
                }
            }
        } else {
            console.log('====================================');
            console.log('商户当前所持有的微信支付平台证书序列号serial_no:' + serial_no);
            console.log('微信支付平台证书序列号wechatpay_serial:' + wechatpay_serial);
            console.log('证书序列号不匹配，需要重新获取证书序列号！');
            console.log('====================================');
        }
        response.status(200);
        return {
            "code": "SUCCESS",
            "message": ""
        }
    }


    // 处理支付宝returnURL通知
    async handlingAliReturnUrl(query: AliReturnUrlQuery, response: Response) {
        const order = await this.oderService.getOrderByNumber(query.out_trade_no);
        if (order) {

        }
        return
    }

    async handlingNotificationsToAli(body: AliPayNoticeBody) {
        const aliSdk = new AliConfig()
        // 验签
        const isPass = aliSdk.aliPay.checkNotifySign(body);
        console.log('验签', isPass);

        if (isPass) {
            // 查看数据库是否有此订单
            const order = await this.oderService.getOrderByNumber(body.out_trade_no);
            // 当前用户订单状态是否已完结
            if (order && order.pay_state === 'NOTPAY') {
                if (body.trade_status === 'TRADE_SUCCESS') {
                    order.pay_state = 'SUCCESS';
                    order.pay_state_desc = '支付成功';
                    order.pay_method = 'ali';
                    order.pay_success_time = body.gmt_payment;
                    order.receipt_price = parseFloat(body.receipt_amount);
                    const orderId = order.id;
                    delete order.id;
                    await this.oderService.update(orderId, order)
                    return 'success'
                }
            }
        }
    }

    async noticeVerification(orderNumber: string): Promise<boolean> {
        const order = await this.oderService.getOrderByNumber(orderNumber);
        if (order) {

        }

        return false
    }
}


interface AliPayNoticeBody {
    gmt_create: string,
    charset: string,
    gmt_payment: string,
    notify_time: string,
    subject: string,
    sign: string,
    buyer_id: string,
    invoice_amount: string,
    version: string,
    notify_id: string,
    fund_bill_list: string,
    notify_type: string,
    out_trade_no: string,
    total_amount: string,
    trade_status: string,
    trade_no: string,
    auth_app_id: string,
    receipt_amount: string,
    point_amount: string,
    buyer_pay_amount: string,
    app_id: string,
    sign_type: string,
    seller_id: string
}